# ALaw Encode Decode Test

# Author: zhanzr21 @ 21ic BBS

#

# If you just want to do G711 A-Law encode/decode, use the audioop package,

# This script is just for analysis and study of the algorithm itself.

import math

# Byte format test
LineData = [i for i in range(-4096, 4096)]
# normalization
NormaData = [i / 4096 for i in LineData]
A = 87.6
A_1 = (1 / A)


def alaw_encode(x):
    if abs(x) < A_1:
        return math.copysign(A * abs(x) / (1 + math.log(A)), x)
    if (abs(x) <= 1) and (abs(x) >= A_1):
        return math.copysign((1 + math.log(A * abs(x))) / (1 + math.log(A)), x)

    print("error x range should -1..1")


def alow_decode(y):
    if abs(y) < (1 / (1 + math.log(A))):
        res = abs(y) * (1 + math.log(A)) / A
        return math.copysign(res, y)

    if (abs(y) <= 1) and (abs(y) >= (1 / (1 + math.log(A)))):
        res = math.exp(abs(y) * (1 + math.log(A)) - 1) / A
        return math.copysign(res, y)

        # Should not come here
    print("Error Decode %f", y)


def alaw():
    f_test = open('g711_alaw_test.csv', mode='w')
    for x in NormaData:
        # Encode
        if abs(x) < A_1:
            y = A * abs(x) / (1 + math.log(A))
            y = math.copysign(y, x)
        elif (abs(x) <= 1) and (abs(x) >= A_1):
            y = (1 + math.log(A * abs(x))) / (1 + math.log(A))
            y = math.copysign(y, x)
        else:
            # Should not come here
            print("ErrorEn %f", x)
        yQ = int(y * 128) / 128
        res = 0
        resQ = 0

        # Decode

        if abs(y) < (1 / (1 + math.log(A))):
            res = abs(y) * (1 + math.log(A)) / A
            res = math.copysign(res, y)

        elif (abs(y) <= 1) and (abs(y) >= (1 / (1 + math.log(A)))):
            res = math.exp(abs(y) * (1 + math.log(A)) - 1) / A
            res = math.copysign(res, y)
        else:
            # Should not come here
            print("ErrorDe %f", y)

        # Decode(Quantization)

        if abs(yQ) < (1 / (1 + math.log(A))):
            resQ = abs(yQ) * (1 + math.log(A)) / A
            resQ = math.copysign(resQ, yQ)
        elif (abs(yQ) <= 1) and (abs(yQ) >= (1 / (1 + math.log(A)))):
            resQ = math.exp(abs(yQ) * (1 + math.log(A)) - 1) / A
            resQ = math.copysign(resQ, yQ)
        else:
            # Should not come here
            print("ErrorDeQ %f", yQ)
        # for debug
        f_test.write('%f,%f,%f,%f,%f\n' % (x, y, yQ, res, resQ))
    f_test.close()


def main():
    print("Compute alaw sequence.")
    # alaw()
    d = 1753
    x = (d >> 3) / 4096.0
    y = alaw_encode(x)
    trans_y = y * 128
    yQ = trans_y / 128

    de = alow_decode(y)
    restore_x = int(de * 4096)
    src = restore_x << 3

    print("src=%d,x=%f,y=%f,trans_y=%f,yQ=%f,de=%f,restoreX=%d,src=%d" % (d, x, y, trans_y, yQ, de, restore_x, src))


if __name__ == '__main__':
    main()
